`timescale  1ns/1ps
`include "Func.v"
module Dot_Addr_Gen
#(parameter max_latency = 8) //不同运算延迟不同
(
    input  wire clk,rst_n,Start,
    input  wire [5:0] opcode,
    input  wire [2:0] RAM_CTR,
    output wire Finish, 
    output reg  busy,
    output reg  [4:0] R1_AddrAL,R1_AddrBL,
    output reg  [4:0] R2_AddrAL,R2_AddrBL,
    output reg R1_ena,R1_enb,R2_ena,R2_enb,
    output reg R1_wea,R1_web,R2_wea,R2_web,

    output reg [6:0] Addr_twiddle0,Addr_twiddle1,Addr_twiddle2,Addr_twiddle3
);

//busy 驱动
always@(posedge clk or negedge rst_n)begin
    if(!rst_n) busy<=0;
    else if(Start & ~busy) busy<=1;
    else if(busy & Finish) busy<=0;
end

//******************低位地址*******************//
reg [4:0] AddrL;
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) AddrL<=0;
    else if(Start & ~busy) AddrL<=0;
    else if(busy & Finish ) AddrL<=0;
//    else if(busy & AddrL==5'd15 & (opcode==`PolyMov)) AddrL<=AddrL;
    else if(busy & AddrL==5'd31 ) AddrL<=AddrL;
    else if(busy) AddrL<=AddrL+1;
end

//*****************延迟***********************//
reg [$clog2(max_latency):0]latency;
reg [$clog2(max_latency):0]latency_cnt;
wire latency_finish = latency_cnt == latency;
always@(posedge clk or negedge rst_n) begin     //初始化延迟数
    if(!rst_n) latency <=4'd8;
    else if(Start & ~busy) begin
        case(opcode)
        `PWM1: latency<=4'd8;
        `PWM2: latency<=4'd8;
        `PolyAdd :latency<=4'd5;
        `Encode_ADD : latency<=4'd9;
        `Decode_SUB : latency<=4'd6;
        `Compress10,`Compress4,`Decompress10,`Decompress4,`Compress11,`Compress5,`Decompress11,`Decompress5: latency<=4'd6;
        endcase
    end
    //else if(busy & Finish) latency<=0;
end

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) latency_cnt<=0;
    else if(Start &~busy ) latency_cnt<=0;
//    else if(busy & AddrL==5'd15 & (opcode==`PolyMov)) latency_cnt<=latency_cnt+1;
    else if(busy & AddrL==5'd31) latency_cnt<=latency_cnt+1;
    else if(latency_finish)latency_cnt<=0;
end
assign Finish = latency_finish;
//******************************************//

//***************地址延时********************//
genvar i;
reg [5:0] AddrL_Delay[0:max_latency-1];
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) AddrL_Delay[0] <=5'd0;
    else if(Start & ~busy) AddrL_Delay[0] <=5'd0;
    else if(busy)  AddrL_Delay[0]<=AddrL;
end

generate
    for(i=1;i<max_latency;i=i+1) 
    begin
        always@(posedge clk or negedge rst_n)
        begin
            if(!rst_n) AddrL_Delay[i]<=5'd0;
            else if(busy)  AddrL_Delay[i]<=AddrL_Delay[i-1];
        end
    end
endgenerate
//******************************************//


//*********************输出地址及信号*************//
always@(*)begin
    if(busy) 
    begin
        case(opcode) 
        `PWM1: 
        begin   //PWM1  4块存储区  4个端口 
            case(RAM_CTR[0])
            1'b0 : begin R1_AddrAL = AddrL; R1_AddrBL = AddrL;   //R1读2  R2写2
                            R2_AddrAL = AddrL_Delay[latency-1] ;R2_AddrBL = AddrL_Delay[latency-1];
                            R1_ena = 1'b1; R1_enb = 1'b1; R1_wea = 1'b0 ; R1_web = 1'b0; 
                            R2_ena = 1'b1; R2_enb = 1'b1; R2_wea = 1'b1 ; R2_web = 1'b1;
                        end 
            1'b1 : begin R1_AddrAL = AddrL_Delay[latency-1]; R1_AddrBL = AddrL_Delay[latency-1];   //R1写2  R2读2
                            R2_AddrAL = AddrL ;R2_AddrBL = AddrL;
                            R1_ena = 1'b1; R1_enb = 1'b1; R1_wea = 1'b1 ; R1_web = 1'b1; 
                            R2_ena = 1'b1; R2_enb = 1'b1; R2_wea = 1'b0 ; R2_web = 1'b0;
                        end 
            endcase
        end
        `PWM2: 
        begin
            case(RAM_CTR[0])
            1'b0 : begin R1_AddrAL = AddrL; R1_AddrBL = AddrL;   //R1读2  R2写A
                        R2_AddrAL = AddrL_Delay[latency-1] ;R2_AddrBL = AddrL_Delay[latency-1];
                        R1_ena = 1'b1; R1_enb = 1'b1; R1_wea = 1'b0 ; R1_web = 1'b0; 
                        R2_ena = 1'b1; R2_enb = 1'b0; R2_wea = 1'b1 ; R2_web = 1'b0;
                        end 
            1'b1 : begin R1_AddrAL = AddrL_Delay[latency-1]; R1_AddrBL = AddrL_Delay[latency-1];   //R1写A  R2读2
                        R2_AddrAL = AddrL ;R2_AddrBL = AddrL;
                        R1_ena = 1'b1; R1_enb = 1'b0; R1_wea = 1'b1 ; R1_web = 1'b0; 
                        R2_ena = 1'b1; R2_enb = 1'b1; R2_wea = 1'b0 ; R2_web = 1'b0;
                        end 
            endcase
        end
        `PolyAdd: 
        begin
            R1_web=1'b0; R2_web=1'b0; R1_AddrBL = AddrL; R2_AddrBL = AddrL;  //B端口只能读
            case(RAM_CTR[0])//判断写
                1'b0: begin 
                    R1_AddrAL=AddrL; R2_AddrAL = AddrL_Delay[latency-1]; R2_ena = 1'b1; R2_wea = 1'b1; R1_wea=1'b0; //写在RAM2 A
                    case(RAM_CTR[2:1])
                        2'b01,2'b10: begin R1_ena=1'b0; R1_enb=1'b1; R2_enb=1'b1;   end//RAM1 A空 B读 RAM2 B读 
                        2'b11:       begin R1_ena=1'b1; R1_enb=1'b1; R2_enb=1'b0;   end//RAM1 AB读 RAM2 B空     
                        default:     begin R1_ena=1'b0; R1_enb=1'b0; R2_enb=1'b0;   end//不使能
                    endcase
                    end  
                1'b1: begin 
                    R1_AddrAL = AddrL_Delay[latency-1]; R2_AddrAL=AddrL; R1_ena = 1'b1; R1_wea = 1'b1; R2_wea=1'b0; //写在RAM1  A
                    case(RAM_CTR[2:1])
                        2'b01,2'b10: begin R1_enb=1'b1; R2_ena=1'b0; R2_enb=1'b1;  end//RAM1 B读 RAM2 B读 
                        2'b00:       begin R1_enb=1'b0; R2_ena=1'b1; R2_enb=1'b1;  end//RAM2 AB读 
                        default:     begin R1_enb=1'b0; R2_ena=1'b0; R2_enb=1'b0;  end//不使能
                    endcase
                end  
            endcase
        end
        `Encode_ADD:
            begin
                R1_AddrAL= AddrL_Delay[0];          R1_AddrBL = AddrL_Delay[0];
                R2_AddrAL= {3'b000,AddrL[4],AddrL[3]};  R2_AddrBL = AddrL_Delay[latency-1];
                R1_ena = 1'b1;   R1_enb = 1'b1;                 R1_wea = 1'b0; R1_web = 1'b0;
                R2_ena = AddrL[2:1] ==3'b00;   R2_enb = 1'b1;   R2_wea = 1'b0; R2_web = 1'b1;
            end
        `Decode_SUB:
            begin
                //R1_AddrAL= {3'b000,AddrL_Delay[latency-1][4],AddrL_Delay[latency-1][5],AddrL_Delay[latency-1][3]};
                R2_AddrAL= 5'd0;
                R2_AddrBL= AddrL; 
                R1_AddrAL= {3'b000,AddrL_Delay[latency-1][4],AddrL_Delay[latency-1][3]};
                R1_AddrBL= AddrL;
                R2_ena = 1'b0;                                   R2_enb=1'b1; R2_wea=1'b0; R2_web=1'b0;
                R1_ena = (AddrL_Delay[latency-1][2:0] ==3'b111) |latency_finish;  R1_enb=1'b1; R1_wea=1'b1; R1_web=1'b0;
            end
        `Compress10,`Compress4,`Decompress10,`Decompress4,`Compress11,`Compress5,`Decompress11,`Decompress5:
            begin
                case(RAM_CTR[0])
                1'b0 : begin R1_AddrAL = AddrL; R1_AddrBL = AddrL; //R1  A读  R2 A写
                            R2_AddrAL = AddrL_Delay[latency-1]; R2_AddrBL = AddrL_Delay[latency-1];
                            R1_ena = 1'b1; R1_enb = 1'b0; R1_wea = 1'b0 ; R1_web = 1'b0; 
                            R2_ena = 1'b1; R2_enb = 1'b0; R2_wea = 1'b1 ; R2_web = 1'b0;
                end 
                1'b1 : begin R1_AddrAL = AddrL_Delay[latency-1]; R1_AddrBL = AddrL_Delay[latency-1]; //R1 A写  R2 A读
                        R2_AddrAL = AddrL; R2_AddrBL = AddrL;
                        R1_ena = 1'b1; R1_enb = 1'b0; R1_wea = 1'b1 ; R1_web = 1'b0; 
                        R2_ena = 1'b1; R2_enb = 1'b0; R2_wea = 1'b0 ; R2_web = 1'b0;
                end 
            endcase
            end 
        // `Compare10,`Compare11,`Compare4,`Compare5:
        //     begin
        //         R1_wea=1'b0; R1_web=1'b0; R2_wea=1'b0; R2_web=1'b0;
        //         R1_AddrAL = AddrL;  R1_AddrBL = AddrL_Delay[0];
        //         R2_AddrAL = AddrL;  R2_AddrBL = AddrL_Delay[0];
        //         case(RAM_CTR[2:1])
        //         2'b00: begin  //R2A 读c'  R2B 读c
        //             R1_ena = 1'b0; R1_enb = 1'b0;
        //             R2_ena = 1'b1; R2_enb = 1'b1;
        //         end
        //         2'b01: begin  //R2A 读c'  R1B 读c
        //             R1_ena = 1'b0; R1_enb = 1'b1;
        //             R2_ena = 1'b1; R2_enb = 1'b0;
        //         end
        //         2'b10: begin  //R1A 读c'  R2B 读c
        //             R1_ena = 1'b1; R1_enb = 1'b0;
        //             R2_ena = 1'b0; R2_enb = 1'b1;
        //         end
        //         2'b11: begin  //R1A 读c'  R2B 读c
        //             R1_ena = 1'b1; R1_enb = 1'b1;
        //             R2_ena = 1'b0; R2_enb = 1'b0;
        //         end
        //         endcase
        //     end
        // `PolyMov:
        //     begin
        //         case(RAM_CTR[0])
        //         1'b0: begin //R1 AB 读  R2 AB写
        //             R1_AddrAL = {AddrL[3:0],1'b0};                   R1_AddrBL = {AddrL[3:0],1'b1};
        //             R2_AddrAL = {AddrL_Delay[latency-1][3:0],1'b0};  R2_AddrBL = {AddrL_Delay[latency-1][3:0],1'b1};
        //             R1_ena =1'b1; R1_enb =1'b1; R1_wea =1'b0; R1_web =1'b0;
        //             R2_ena =1'b1; R2_enb =1'b1; R2_wea =1'b1; R2_web =1'b1;
        //         end
        //         1'b1: begin //R2 AB 读  Ra AB写
        //             R2_AddrAL = {AddrL[3:0],1'b0};                   R2_AddrBL = {AddrL[3:0],1'b1};
        //             R1_AddrAL = {AddrL_Delay[latency-1][3:0],1'b0};  R1_AddrBL = {AddrL_Delay[latency-1][3:0],1'b1};
        //             R2_ena =1'b1; R2_enb =1'b1; R2_wea =1'b0; R2_web =1'b0;
        //             R1_ena =1'b1; R1_enb =1'b1; R1_wea =1'b1; R1_web =1'b1;
        //         end
        //         endcase
        //     end
        default:    begin R1_AddrAL = 5'd0; R1_AddrBL = 5'd0;   
                        R2_AddrAL = 5'd0 ;R2_AddrBL = 5'd0;
                        R1_ena = 1'b0; R1_enb = 1'b0; R1_wea = 1'b0 ; R1_web = 1'b0; 
                        R2_ena = 1'b0; R2_enb = 1'b0; R2_wea = 1'b0 ; R2_web = 1'b0;
                    end 
        endcase
    end
    else begin
        R1_AddrAL = 5'd0; R1_AddrBL = 5'd0;   
        R2_AddrAL = 5'd0; R2_AddrBL = 5'd0;
        R1_ena = 1'b0; R1_enb = 1'b0; R1_wea = 1'b0 ; R1_web = 1'b0; 
        R2_ena = 1'b0; R2_enb = 1'b0; R2_wea = 1'b0 ; R2_web = 1'b0;
    end
end

//******************************************//

//*******************AddrTweiddle***********//

 wire [6:0] Addr_twiddle0_temp = {1'b1 ,AddrL, 1'b0 };
 wire [6:0] Addr_twiddle1_temp = Addr_twiddle0_temp;
 wire [6:0] Addr_twiddle2_temp = {1'b1 ,AddrL, 1'b1 };
 wire [6:0] Addr_twiddle3_temp = Addr_twiddle2_temp;
always@(*) begin
    if(busy & opcode == `PWM2) 
    begin  
        Addr_twiddle0={Addr_twiddle0_temp[0], Addr_twiddle0_temp[1],Addr_twiddle0_temp[2],Addr_twiddle0_temp[3],Addr_twiddle0_temp[4],Addr_twiddle0_temp[5],Addr_twiddle0_temp[6]}; 
        Addr_twiddle1={Addr_twiddle1_temp[0], Addr_twiddle1_temp[1],Addr_twiddle1_temp[2],Addr_twiddle1_temp[3],Addr_twiddle1_temp[4],Addr_twiddle1_temp[5],Addr_twiddle1_temp[6]}; 
        Addr_twiddle2={Addr_twiddle2_temp[0], Addr_twiddle2_temp[1],Addr_twiddle2_temp[2],Addr_twiddle2_temp[3],Addr_twiddle2_temp[4],Addr_twiddle2_temp[5],Addr_twiddle2_temp[6]}; 
        Addr_twiddle3={Addr_twiddle3_temp[0], Addr_twiddle3_temp[1],Addr_twiddle3_temp[2],Addr_twiddle3_temp[3],Addr_twiddle3_temp[4],Addr_twiddle3_temp[5],Addr_twiddle3_temp[6]}; 
    end
    else 
    begin 
        Addr_twiddle0=7'd0;
        Addr_twiddle1=7'd0;
        Addr_twiddle2=7'd0;
        Addr_twiddle3=7'd0;
    end
end


//******************************************//
endmodule


// module Dot_Addr_Gen_tb;

// reg clk,rst_n,Start;
// reg [5:0] opcode;
// reg [2:0] RAM_CTR;
// wire [4:0] DOT_R1_AddrAL,DOT_R1_AddrBL,DOT_R2_AddrAL,DOT_R2_AddrBL;
// wire DOT_R1_ena,DOT_R1_enb,DOT_R2_ena,DOT_R2_enb,DOT_R1_wea,DOT_R1_web,DOT_R2_wea,DOT_R2_web;
// wire DOT_ROM_ena;
// Dot_Addr_Gen#(.max_latency(6))  theDot_Addr_Gen//不同运算延迟不同
// (
//     .clk(clk),.rst_n(rst_n),.Start(Start),
//     .opcode(opcode),
//     .RAM_CTR(RAM_CTR),
//     .Finish(), 
//     .busy(),
//     .R1_AddrAL(DOT_R1_AddrAL),.R1_AddrBL(DOT_R1_AddrBL),
//     .R2_AddrAL(DOT_R2_AddrAL),.R2_AddrBL(DOT_R2_AddrBL),
//     .R1_ena(DOT_R1_ena),.R1_enb(DOT_R1_enb),.R2_ena(DOT_R2_ena),.R2_enb(DOT_R2_enb),
//     .R1_wea(DOT_R1_wea),.R1_web(DOT_R1_web),.R2_wea(DOT_R2_wea),.R2_web(DOT_R2_web),
//     .Addr_twiddle0(),.Addr_twiddle1()
// );


// initial
//  begin
//  clk=0;
//  rst_n=1;
//  Start=0;
//  opcode = `PWM1;
//  RAM_CTR = `R1_TO_R2;
//  #20 rst_n=0;
//  #20 rst_n=1;
//  #20 Start=1;
//  #20 Start=0;
//  #2000;
//  end
//  always# 5 clk=~clk;

// endmodule